//
//  HMHomeTableViewController.swift
//  大深圳微博01
//
//  Created by shenzhenIOS on 16/4/8.
//  Copyright © 2016年 shenzhenIOS. All rights reserved.
//

import UIKit

import SVProgressHUD
import SVPullToRefresh

/*
    导航栏显示什么内容不是看导航控制器,看导航控制器当前正在显示的子控制器
*/
class HMHomeTableViewController: HMBaseTableViewController {
    
    /// 刷新控件
    private lazy var pullDownRefreshControl: HMPullDownRefreshControl = HMPullDownRefreshControl()
    
    /// 微博模型
    var statuses: [HMStatus]? {
        didSet {
            // 只要微博数据改变了就刷新微博数据
            HMPrint("总得微薄数据: \(statuses?.count)")
            self.tableView.reloadData()
        }
    }
    
    private let ReuseIdentifier = "ReuseIdentifier"

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 用户没有登录不需要做一下操作
        if !HMUserAccountViewModel.sharedInstance.userLogin {
            HMPrint("没有登录不做一下操作")
            return
        }
        
        setupNavigationBar()
        prepareTableView()
    }
    
    private func prepareTableView() {
        // 去掉分割线
        tableView.separatorStyle = UITableViewCellSeparatorStyle.None
        // 注册cell
        tableView.registerClass(HMStatusCell.self, forCellReuseIdentifier: ReuseIdentifier)
        
        // 1.cell的高度设置为UITableViewAutomaticDimension
        tableView.rowHeight = UITableViewAutomaticDimension
        
        // 2.预估行高,等cell要显示的时候才回去计算真实的高度
//        tableView.estimatedRowHeight = 200
        
        
        // MARK: - 下拉刷新相关
        // 将刷新控件添加到tableView里面
        tableView.addSubview(pullDownRefreshControl)
        
        // 03.准备刷新的闭包
        pullDownRefreshControl.pullDownRefreshHandler = { () -> () in
            HMPrint("控制器开始下拉刷新")
            
            self.loadNewStatus()
        }
        
        // 让控件进入到刷新状态
        pullDownRefreshControl.startRefreshing()
        // MARK: - 下拉刷新相关结束
        
        // 上拉加载更多, 等下拉刷新有数据后,才有上拉加载这个功能
//        tableView.addInfiniteScrollingWithActionHandler { () -> Void in
//            // 上拉加载数据
//            
//            HMPrint("上拉加载数据")
//            self.loadMoreStatus()
//        }
    }
    
    /// 上拉加载更多老的数据
    private func loadMoreStatus() {
        // 获取id最小的微博
        let max_id = self.statuses?.last?.id ?? 0
        
        // 一条微博数据都没有,就不去上拉加载更多数据
        if max_id == 0 {
            HMPrint("没有微博数据,不去上拉加载更多数据")
            return
        }
        
        // 加载比 max_id 还小得微博
        HMStatusViewModel.sharedInstance.loadStatus(0, max_id: max_id) { (statuses, error) -> () in
            // 让刷新控件结束刷新
            self.tableView.infiniteScrollingView.stopAnimating()
            
            if error != nil {
                HMPrint("上拉加载更多微博数据失败了: \(error)")
                return
            }
            
            let count = statuses?.count ?? 0
            
            HMPrint("加载更多的数据条数: \(count)")
            
            if count == 0 {
                // 没有加载更多的数据了
                HMPrint("没有加载更多的数据了")
                SVProgressHUD.showErrorWithStatus("没有加载更多的数据了")
                return
            }
            
            // 拼接数据,老得微博数据拼接到现有数据的后面
            let s = self.statuses! + statuses!
            self.statuses = s
        }
    }
    
    /// 下拉加载新的微薄数据
    private func loadNewStatus() {
        // 获取ID最大的微博, 第一条微博就是ID最大的微博, 当第一次进入刷新,一条微博都没有id = 0, 加载最新20条
        let since_id = self.statuses?.first?.id ?? 0
        
        // 01.加载数据,准备了闭包,传递给了 loadStatus 的 loadStatusCallback
        HMStatusViewModel.sharedInstance.loadStatus(since_id, max_id: 0) { (statuses, error) -> () in
            // 加载数据完成了.让刷新控件完成刷新
            self.pullDownRefreshControl.endRefreshing()
            
            if error != nil {
                HMPrint("获取微博数据失败了: \(error)")
                SVProgressHUD.showErrorWithStatus("您的网络不给力...")
                return
            }
            
            // 判断返回微博的数量
            let count = statuses?.count ?? 0
            HMPrint("加载了微薄数据: \(count)")
            // 如果是第一次加载20条,不需要显示
            if since_id != 0 {
                // 用户手动拖拽,显示下拉刷新的条数
                self.showTipLabel(count)
            }
            
            if count == 0 {
                HMPrint("没有加载到微博数据")
                
                if since_id == 0 {
                    SVProgressHUD.showErrorWithStatus("没有加载到微博数据")
                }
                return
            }
            
            // 加载微博成功,将微博数据保存起来,让tableView去显示
            // 判断,如果 since_id = 0
            if since_id == 0 {
                self.statuses = statuses
                
                // 第一次进来tableView没有数据since_id = 0 ,加载最新20条,有数据后才添加上拉加载更多这个功能
                self.tableView.addInfiniteScrollingWithActionHandler { () -> Void in
                    // 上拉加载数据
                    self.loadMoreStatus()
                }
            } else {
                // 如果since_id != 0, 将返回的数据拼接到现有数据前面
                // 数组直接使用加号拼接
                let s = statuses! + self.statuses!
                
                // 将拼接好的数据赋值给self.statuses
                self.statuses = s
            }
        }
    }
    
    /// 显示下拉数据提示
    /// count:更新数据的条数
    private func showTipLabel(count: Int) {
        
        
        // label放到导航栏里面 y = -(状态栏的高度+自己的高度)
        let y = -(UIApplication.sharedApplication().statusBarFrame.height + TipLabelHeight)
        tipLabel.frame = CGRect(x: 0, y: y, width: UIScreen.mainScreen().bounds.width, height: TipLabelHeight)
        // 设置文字内容
        tipLabel.text = count == 0 ? "没有新的微博数据" : "下拉刷新了 \(count) 条微博数据"
        
        // 快速拖动,会发现动画还没有完成,又来一个动画,动画叠加
        // UIView动画,底层其实也是核心动画
        /// 获取layer上面正在执行动画的key
        if let keys = tipLabel.layer.animationKeys() {
            HMPrint("正在执行动画, keys: \(keys)")
            // 正在执行动画, 不要后面的动画了
            return
        }
        
        // label动画
        UIView.animateWithDuration(1, animations: { () -> Void in
            self.tipLabel.frame = CGRect(x: 0, y: TipLabelHeight, width: UIScreen.mainScreen().bounds.width, height: TipLabelHeight)
            }) { (_) -> Void in
                // 停一会,在动画到屏幕上面去
                // 返回回去的动画
                UIView.animateWithDuration(1, delay: 0.5, options: [], animations: { () -> Void in
                    self.tipLabel.frame = CGRect(x: 0, y: -(UIApplication.sharedApplication().statusBarFrame.height + TipLabelHeight), width: UIScreen.mainScreen().bounds.width, height: TipLabelHeight)
                    }, completion: { (_) -> Void in
                        // 控制器一直存在一个label，动画完成不移除,只是在屏幕外面,用户看不到
                })
        }
    }
    
    private func setupNavigationBar() {
        // 左边
        navigationItem.leftBarButtonItem = UIBarButtonItem(imageName: "navigationbar_friendsearch", target: self, action: Selector("didClickPerson:"))
        
        // 右边
        navigationItem.rightBarButtonItem = UIBarButtonItem(imageName: "navigationbar_pop", target: self, action: "didClickQRCode:")
        
        // ?? 前面如果为nil 就使用 ?? 后面的内容
        // ?? 前面有值,直接使用前面的值
        let name = HMUserAccountViewModel.sharedInstance.userAccount?.screen_name ?? "没有名称"

        // title按钮
        let titleButton = HMHomeTitleButton(title: name)
        titleButton.addTarget(self, action: Selector("didClickTitleButton:"), forControlEvents: UIControlEvents.TouchUpInside)
        navigationItem.titleView = titleButton
    }
    
    // MARK: - 按钮点击事件
    @objc private func didClickTitleButton(button: UIButton) {
        // 切换按钮的选中状态
        button.selected = !button.selected
        UIView.animateWithDuration(HMDefautlAnimDuration) { () -> Void in
            button.imageView?.transform = button.selected ? CGAffineTransformMakeRotation(CGFloat(M_PI - 0.001)) : CGAffineTransformIdentity
        }
    }
    
    @objc private func didClickPerson(button: UIButton) {
        HMPrint("button: \(button)")
    }
    
    @objc private func didClickQRCode(button: UIButton) {
        HMPrint("button: \(button)")
    }
    
    // MARK: - 下拉刷新数量label
    private lazy var tipLabel: UILabel = {
        let label = UILabel(fontSize: 14, textColor: UIColor.whiteColor())
        
        label.backgroundColor = UIColor.orangeColor()
        label.textAlignment = NSTextAlignment.Center
        
        // 只需要添加一次
        self.navigationController?.navigationBar.insertSubview(label, atIndex: 0)
        
        return label
    }()
}

/*
    tableView优化:
        1.cell重用
        2.dequeueReusableCellWithIdentifier:forIndexPath:(会调用heightForRowAtIndexPath) 和 dequeueReusableCellWithIdentifier (后面这个不会再次调用heightForRowAtIndexPath)
            2.1 tableView在cell显示之前会调用heightForRowAtIndexPath,有多少个cell就会调用多少次, 算contentSize
            2.2 使用了预估行高,并不会再显示之前去计算获取所有的行高,根据预估行高和实际行高来获取cell的行高,先根据预估行高计算好要先获取几个cell,如果计算的这几个cell高度确实够(高度能超出屏幕的高度就不计算了.如果不够还会计算),目的也是让contentSize大于屏幕,就能滚动,后面要显示,才来计算行高, 会发现滚动条会跳
        3.cell的高度是根据内容变化的时候,只计算一次,将高度缓存起来
        4.下载图片使用SDWebImage(异步操作)
        5.cellForRowAtIndexPath不要做耗时操作
            1.读取文件,写入文件,最好是放到子线程,或先读取好,在让tableView去显示
            2.解压资源
            3.尽量少得计算计算,最好是先计算好,cellForRowAtIndexPath只做显示
            4.尽量不要去添加和移除view, 现将会用到的控件懒加载,要就显示,不要就隐藏
        6.tableView滚动的时候,不要去做动画
        7.cell里面的控件,约束最好不要使用remake,动态添加约束是比较耗性能的
        8.cell里面的控件,背景最好是不透明的 (图层混合), view的背景颜色 clearColor 尽量少
        9.图片圆角不要使用 layer.cornerRadius
        10.图层最好不要使用阴影, 阴影会导致离屏渲染
        11.异步绘制
        12.栅格化
        13.AsyncDisplayKit -> 不使用UIKit (UIView) ->  (Node)
        14.借助工具来测试性能
*/

// MARK: - 扩展 HMHomeTableViewController,将tableView的数据源方法放到这里
extension HMHomeTableViewController {
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        
        // 获取模型
        let status = self.statuses![indexPath.row]
        
        // 判断模型里面之前有没有缓存过行高
        if status.rowHeight != nil {
            // 之前保存过行高,直接返回行高
//            print("heightForRowAtIndexPath: \(indexPath.row), 使用缓存高度: \(status.rowHeight!)")
            return status.rowHeight!
        }
        
        // 自己算行高: AutoLayout自动约束
        // 让cell设置对应内容,可以直接获高度,这个cell不参与显示
        let cell = tableView.dequeueReusableCellWithIdentifier(ReuseIdentifier) as! HMStatusCell
        
        // 将模型给cell, cell里面的控件设置模型里面的内容,会更新cell里面控件的约束
        cell.status = status
        
        // 我们最终只需要获取高度,根据view的约束获取大小
        let height = cell.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
        
        // 保存行高
        status.rowHeight = height
        
//        print("heightForRowAtIndexPath: \(indexPath.row), 计算高度: \(height)")
        
        return height
    }
//    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
//        <#code#>
//    }
    // 返回cell的数量
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.statuses?.count ?? 0
    }
    
    // 返回每个cell的内容
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier(ReuseIdentifier) as! HMStatusCell
//        let cell = tableView.dequeueReusableCellWithIdentifier(ReuseIdentifier, forIndexPath:
//            indexPath) as! HMStatusCell
        
        // cell显示之前,将模型传递给cell
        cell.status = self.statuses?[indexPath.row]
        
        return cell
    }
    
    /// cell不要高亮
    override func tableView(tableView: UITableView, shouldHighlightRowAtIndexPath indexPath: NSIndexPath) -> Bool {
        return false
    }
    
//    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
//        tableView.deselectRowAtIndexPath(indexPath, animated: true)
//    }
    
    // 监听scrollView的滚动
//    override func scrollViewDidScroll(scrollView: UIScrollView) {
        // 可以在这里监听到tableView的滚动,设置刷新控件的状态
        // 在控制器里面来设置刷新控件的状态其实不好,1.控制器需要对刷新控件非常了解才行 2.刷新控件以来控制器,到其他地方使用非常麻烦
        // 刷新控件监听tableView的滚动最好是自己来做
//    }
}
